﻿using Library.Collections;
using Library.Collections.Generic;
using Library.Collections.Specialized;
using Library.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Library.Linq
{
    public static class Tree
    {
        public static IStack<T> Clone<T>(this IStack<T> stack, Direction direction, Access access)
        {
            throw new NotImplementedException();
        }



        internal class BestFirstQueryProvider : IQueryProvider
        {
            public static BestFirstQueryProvider Instance = new BestFirstQueryProvider();

            public IQueryable<TElement> CreateQuery<TElement>(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }

            public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }

            public TResult Execute<TResult>(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }

            public object Execute(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }
        }

        internal class BreadthFirstQueryProvider : IQueryProvider
        {
            public static BreadthFirstQueryProvider Instance = new BreadthFirstQueryProvider();

            public IQueryable<TElement> CreateQuery<TElement>(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }

            public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }

            public TResult Execute<TResult>(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }

            public object Execute(System.Linq.Expressions.Expression expression)
            {
                throw new NotImplementedException();
            }
        }

        internal class DepthFirstQueryProvider : IQueryProvider
        {
            public static DepthFirstQueryProvider Instance = new DepthFirstQueryProvider();

            public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
            {
                throw new NotImplementedException();
            }

            public IQueryable CreateQuery(Expression expression)
            {
                throw new NotImplementedException();
            }

            public TResult Execute<TResult>(Expression expression)
            {
                throw new NotImplementedException();
            }

            public object Execute(Expression expression)
            {
                throw new NotImplementedException();
            }
        }



        public static ITreeValue<TResult> Select<TNode, TResult>(this ITreeReadOnly<TNode> tree, Expression<Func<TNode, TResult>> selector)
            where TNode : ITreeReadOnly<TNode>
        {
            throw new NotImplementedException();
        }



        public static IQueryable<IQueryable<TNode>> BestFirst<TNode, TKey>(this TNode tree, Expression<Func<IQueryable<TNode>, TKey>> keySelector)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");

            return BestFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode), typeof(TKey)),
                Expression.Constant(tree),
                Expression.Quote(keySelector))
            );
        }
        public static IQueryable<IQueryable<TNode>> BestFirst<TNode, TKey>(this TNode tree, Expression<Func<IQueryable<TNode>, TKey>> keySelector, IComparer<TKey> comparer)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");
            if (comparer == null)
                throw new ArgumentNullException("comparer");

            return BestFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode), typeof(TKey)),
                Expression.Constant(tree),
                Expression.Quote(keySelector),
                Expression.Constant(comparer))
            );
        }
        public static IQueryable<IQueryable<TNode>> BestFirst<TNode, TKey>(this TNode tree, Expression<Func<IQueryable<TNode>, TKey>> keySelector, IStack<TNode> stack)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");
            if (stack == null)
                throw new ArgumentNullException("stack");

            return BestFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode), typeof(TKey)),
                Expression.Constant(tree),
                Expression.Quote(keySelector),
                Expression.Constant(stack))
            );
        }
        public static IQueryable<IQueryable<TNode>> BestFirst<TNode, TKey>(this TNode tree, Expression<Func<IQueryable<TNode>, TKey>> keySelector, IComparer<TKey> comparer, IStack<TNode> stack)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");
            if (comparer == null)
                throw new ArgumentNullException("comparer");
            if (stack == null)
                throw new ArgumentNullException("stack");

            return BestFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode), typeof(TKey)),
                Expression.Constant(tree),
                Expression.Quote(keySelector),
                Expression.Constant(comparer),
                Expression.Constant(stack))
            );
        }

        public static IQueryable<IQueryable<TNode>> BreadthFirst<TNode>(this TNode tree)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");

            return BreadthFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode)),
                Expression.Constant(tree))
            );
        }
        public static IQueryable<IQueryable<TNode>> BreadthFirst<TNode>(this TNode tree, IStack<TNode> stack)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");
            if (stack == null)
                throw new ArgumentNullException("stack");

            return BreadthFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode)),
                Expression.Constant(tree),
                Expression.Constant(stack))
            );
        }

        public static IQueryable<IQueryable<TNode>> DepthFirst<TNode>(this TNode tree)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");

            return DepthFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode)),
                Expression.Constant(tree))
            );
        }
        public static IQueryable<IQueryable<TNode>> DepthFirst<TNode>(this TNode tree, IStack<TNode> stack)
            where TNode : ITreeReadOnly<TNode>
        {
            if (tree == null)
                throw new ArgumentNullException("tree");
            if (stack == null)
                throw new ArgumentNullException("stack");

            return DepthFirstQueryProvider.Instance.CreateQuery<IQueryable<TNode>>
            (
                Expression.Call(null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TNode)),
                Expression.Constant(tree),
                Expression.Constant(stack))
            );
        }
    }
}
